package com.c6906.vdam.das.service.impl;

import com.alibaba.fastjson.JSON;
import com.c6906.vdam.das.config.redis.RedisUtils;
import com.c6906.vdam.das.dao.FunctionalAreaDAO;
import com.c6906.vdam.das.dao.VehiclesDAO;
import com.c6906.vdam.das.model.dto.FunctionalAreaDTO;
import com.c6906.vdam.das.model.entity.FunctionalArea;
import com.c6906.vdam.das.service.AreaCheckService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@Service
public class AreaCheckServiceImpl implements AreaCheckService {
    public static final Logger logger = LoggerFactory.getLogger(AreaCheckServiceImpl.class);
    @Resource
    FunctionalAreaDAO FunctionalAreaDAO;
    @Resource
    RedisUtils redisUtils;
    @Resource
    private VehiclesDAO vehiclesDAO;

    // 计算矩形区域的最小 x 和 y
    private double[] minArea(double[][] area) {
        double minX = area[0][0];
        double minY = area[0][1];
        for (double[] row : area) {
            if (row[0] < minX) {
                minX = row[0];
            }
            if (row[1] < minY) {
                minY = row[1];
            }
        }
        return new double[]{minX, minY};
    }

    // 计算矩形区域的最大 x 和 y
    private double[] maxArea(double[][] area) {
        double maxX = area[0][0];
        double maxY = area[0][1];
        for (double[] row : area) {
            if (row[0] > maxX) {
                maxX = row[0];
            }
            if (row[1] > maxY) {
                maxY = row[1];
            }
        }
        return new double[]{maxX, maxY};
    }

    // 判断点是否在矩形区域内
    private boolean isPoiWithinBox(double[] poi, double[] minArea, double[] maxArea) {
        double x1 = minArea[0];
        double y1 = minArea[1];
        double x2 = maxArea[0];
        double y2 = maxArea[1];
        return poi[0] > x1 && poi[0] < x2 && poi[1] > y1 && poi[1] < y2;
    }

    // 判断射线与边是否有交点
    private boolean isRayIntersectsSegment(double[] poi, double[] sPoi, double[] ePoi) {
        if (sPoi[1] == ePoi[1]) {
            return false;
        }
        if (sPoi[1] > poi[1] && ePoi[1] > poi[1]) {
            return false;
        }
        if (sPoi[1] < poi[1] && ePoi[1] < poi[1]) {
            return false;
        }
        if (sPoi[1] == poi[1] && ePoi[1] > poi[1]) {
            return false;
        }
        if (ePoi[1] == poi[1] && sPoi[1] > poi[1]) {
            return false;
        }
        if (sPoi[0] < poi[0] && ePoi[0] < poi[0]) {
            return false;
        }
        double xseg = ePoi[0] - (ePoi[0] - sPoi[0]) * (ePoi[1] - poi[1]) / (ePoi[1] - sPoi[1]);
        return xseg >= poi[0];
    }

    @Override
    // 判断点是否在禁停区域内
    public boolean isPoiWithinNoParkingArea(String lng, String lat, double[][] noParkingArea, double[] minArea, double[] maxArea) {
        double[] poi = new double[]{Double.parseDouble(lng), Double.parseDouble(lat)};
        if (!isPoiWithinBox(poi, minArea, maxArea)) {
            return false;
        }
        int polyLen = noParkingArea.length;
        int sinsc = 0;
        for (int i = 0; i < polyLen - 1; i++) {
            if (isRayIntersectsSegment(poi, noParkingArea[i], noParkingArea[i + 1])) {
                sinsc++;
            }
        }
        return sinsc % 2 == 1;
    }

    @Override
    public void initFunctionalArea() {
        List<FunctionalArea> functionalAreas = FunctionalAreaDAO.selectAll();
        for (FunctionalArea data : functionalAreas) {
            if (data.getIsDeleted() != 1 && data.getStatus() != 99 && !data.getMapInfo().isEmpty()) {
                try {
                    FunctionalAreaDTO functionalAreaDTO = parseClobToList(data);
                    List<Map<String, Double>> noParkingArea = functionalAreaDTO.getMapInfo();
                    double[][] area = new double[noParkingArea.size()][2];
                    for (int i = 0; i < noParkingArea.size(); i++) {
                        area[i][0] = noParkingArea.get(i).get("lng");
                        area[i][1] = noParkingArea.get(i).get("lat");
                    }
                    functionalAreaDTO.setArea(area);
                    functionalAreaDTO.setMinArea(minArea(area));
                    functionalAreaDTO.setMaxArea(maxArea(area));
                    redisUtils.set("Fence:" + functionalAreaDTO.getId(), JSON.toJSONString(functionalAreaDTO));
                    redisUtils.setAdd("FenceIds", String.valueOf(functionalAreaDTO.getId()));
                    logger.info("initFunctionalArea: {}", functionalAreaDTO.getId());
                } catch (Exception e) {
                    logger.error("初始化禁区异常,id:{}", data.getId());
                }
            } else {
                redisUtils.delete("Fence:" + data.getId());
            }
        }
    }

    @Override
    @Cacheable(value = "areaWhiteList", key = "#vehiclesCode", condition = "#vehiclesCode != null")
    public List<Long> getAreaWhiteListByVehiclesCode(String vehiclesCode) {
        return vehiclesDAO.getAreaWhiteListByVehiclesCode(vehiclesCode);
    }

    public FunctionalAreaDTO parseClobToList(FunctionalArea area) {
        // 创建 ObjectMapper 对象
        ObjectMapper objectMapper = new ObjectMapper();
        FunctionalAreaDTO functionalAreaDTO = new FunctionalAreaDTO();
        try {
            BeanUtils.copyProperties(area, functionalAreaDTO);
            // 将 JSON 字符串转换为 List<Map<String, Double>> 对象
            List<Map<String, Double>> list = objectMapper.readValue(area.getMapInfo(), new TypeReference<List<Map<String, Double>>>() {
            });
            functionalAreaDTO.setMapInfo(list);
            return functionalAreaDTO;
        } catch (Exception e) {
            logger.error("parseClobToList error: {}", e.getMessage());
            return null;
        }
    }
}
